package com.gengzp.rpc.core.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.gengzp.rpc.annotation.RemoteTransactional;
import com.gengzp.rpc.core.RpcInvocationCoreFunc;
import com.gengzp.rpc.core.RpcRequestIdentificationCoreFunc;
import com.gengzp.rpc.exception.RpcException;
import com.gengzp.rpc.factory.RpcBeanInstanceFactory;
import com.gengzp.rpc.model.common.req.RpcRequest;
import com.gengzp.rpc.model.common.resp.RpcResponse;
import com.gengzp.rpc.model.serviceRegistration.resp.SearchServiceRegistrationResp;
import com.gengzp.rpc.tools.RpcEnvironmentVariableReader;
import com.gengzp.rpc.tools.RpcHttpRequester;
import com.gengzp.rpc.tools.RpcJsonConvertor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

import static com.gengzp.rpc.constants.RpcRequestCodeConstants.RPC_REQUEST_SUCCESS;
import static com.gengzp.rpc.constants.RpcRequestHeaderFieldNameConstants.REQUEST_ID;
import static com.gengzp.rpc.constants.RpcUriConstants.RPC_PRODUCER_CONTROLLER_URI;
import static com.gengzp.rpc.constants.RpcUriConstants.RPC_PRODUCER_METHOD_URI;

/**
 * @ClassName RpcInvocationCoreFuncImpl
 * @Description rpc调用核心方法接口实现类
 * @Author gengzp
 * @Date 2025/8/22 9:53
 */
@Component
public class RpcInvocationCoreFuncImpl implements RpcInvocationCoreFunc {

    @Autowired
    private RpcBeanInstanceFactory rpcBeanInstanceFactory;

    @Autowired
    private RpcRequestIdentificationCoreFunc rpcRequestIdentificationCoreFunc;

    /**
     * 发起调用远程服务的http请求
     *
     * @param remoteCallUrl           远程调用url
     * @param rpcRequest              请求参数
     * @param remoteCallRequestHeader 请求头信息
     * @return 调用返回结果
     */
    public Object doHttpRequest2RemoteService(String remoteCallUrl,
                                              RpcRequest rpcRequest,
                                              Map<String, String> remoteCallRequestHeader,
                                              Type returnTargetType) throws RpcException {
        RpcResponse<Object> result = RpcHttpRequester.post(
                remoteCallUrl, rpcRequest, remoteCallRequestHeader, new TypeReference<>() {
                });
        if (result == null) {
            throw RpcException.get("未获取到远程调用响应信息");
        }

        // 若远程方法内部加入了远程事务, 那么当前请求也加入远程事务中
        rpcRequestIdentificationCoreFunc.saveEnableRemoteTransactionFlag(result.getEnableRemoteTransactionFlag());

        // 返回码为失败, 则抛出异常
        if (result.getCode() != RPC_REQUEST_SUCCESS) {
            throw RpcException.get(result.getMessage());
        }

        return RpcJsonConvertor.convertObjToSpecificType(result.getData(), returnTargetType);
    }

    /**
     * 获取对应服务的所有在线实例地址
     *
     * @param remoteServiceName 远程服务名
     * @return 远程服务地址
     */
    @Override
    public List<String> getRemoteServiceAddresses(String remoteServiceName) throws RpcException {
        return rpcBeanInstanceFactory.getRpcRemoteServiceRouteStrategy()
                .getServiceInstanceAddressByServiceName(remoteServiceName);
    }

    @Override
    public List<SearchServiceRegistrationResp> getAllServiceRegistrationInformationByServiceName(String serviceName) throws RpcException {
        return rpcBeanInstanceFactory.getRpcRemoteServiceRouteStrategy()
                .getServiceRegistrationInformationByServiceName(serviceName);
    }

    /**
     * 获取远程服务地址
     * <p> 内置简单的随机作为负载均衡机制 </p>
     *
     * @param remoteServiceName 远程服务名
     * @return 远程服务地址
     */
    public String getRemoteServiceAddress(String remoteServiceName) throws RpcException {
        // 1.根据服务名获取所有的在线远程服务实例地址
        List<String> remoteServiceAddresses = rpcBeanInstanceFactory.getRpcRemoteServiceRouteStrategy()
                .getServiceInstanceAddressByServiceName(remoteServiceName);
        if (remoteServiceAddresses == null || remoteServiceAddresses.isEmpty()) {
            throw RpcException.get("未找到远程服务实例, 请检查对应服务的实例在线状态");
        }

        // 2.进行简单的负载均衡 (随机), 并拼接完整的请求url
        return remoteServiceAddresses.get(
                ThreadLocalRandom.current().nextInt(remoteServiceAddresses.size())) +
                RPC_PRODUCER_CONTROLLER_URI + RPC_PRODUCER_METHOD_URI;
    }

    /**
     * 构建远程调用请求参数
     *
     * @param remoteServiceName 远程服务名
     * @param proxy             代理对象
     * @param method            远程方法
     * @param args              参数列表
     * @return 请求参数
     */
    public RpcRequest buildRpcRequest(String remoteServiceName, Object proxy, Method method, Object[] args) {
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setRequestId(rpcRequestIdentificationCoreFunc.getCurrentRequestIdentification().getRequestId());
        rpcRequest.setConsumerServiceName(RpcEnvironmentVariableReader.getCurrentServiceName());
        rpcRequest.setProducerServiceName(remoteServiceName);
        rpcRequest.setInterfaceClass(proxy.getClass().getInterfaces()[0]);
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setEnableRemoteTransactionFlag(method.isAnnotationPresent(RemoteTransactional.class));
        rpcRequest.setParameterTypes(method.getParameterTypes());
        rpcRequest.setArgs(args);
        return rpcRequest;
    }

    /**
     * 获取用户自定义远程调用请求头
     *
     * @return 请求头信息
     */
    public Map<String, String> getCustomRemoteCallRequestHeader() {
        Map<String, String> customRequestHeader = rpcBeanInstanceFactory
                .getRpcRequestInterceptor().getRemoteCallRequestHeader();
        // 将当前请求的唯一id也添加到请求头中, 让远程服务的调用共享同一个请求标识
        customRequestHeader.put(REQUEST_ID, rpcRequestIdentificationCoreFunc.getCurrentRequestIdentification().getRequestId());
        return customRequestHeader;
    }

    /**
     * 转换参数列表的对象为指定类型
     *
     * @param args           参数列表
     * @param parameterTypes 参数类型列表
     * @return 转换后的参数列表
     */
    public Object[] convertArgsToSpecificType(Object[] args, Class<?>[] parameterTypes) {
        if (args == null || args.length == 0) {
            return new Object[0];
        }
        Object[] newArgs = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            newArgs[i] = RpcJsonConvertor.convertObjToSpecificType(args[i], parameterTypes[i]);
        }
        return newArgs;
    }

    @Override
    public String lowercaseFirstLetter(String str) {
        // 处理null或空字符串
        if (str == null || str.isEmpty()) {
            return str;
        }

        // 处理单字符字符串
        if (str.length() == 1) {
            return str.toLowerCase();
        }

        // 取第一个字符转为小写，拼接剩余部分
        char firstChar = str.charAt(0);
        String rest = str.substring(1);
        return Character.toLowerCase(firstChar) + rest;
    }

}
